#include "StdAfx.h"
#include "Thread/HighPerformanceTimerThread.h"
#include "Utils/FastBlockQueue.h"
#include "Utils/Callbackable.h"

HighPerformanceTimerThread::HighPerformanceTimerThread(FastBlockQueue& queue)
:m_queue(queue)
{

}

void HighPerformanceTimerThread::AddTimer(UINT handler,UINT period,Callbackable* callback)
{
	Timer timer = {0};
	//		timer.dueTime = dueTime;
	timer.period = period;
	timer.counter = 0;
	timer.callback = callback;
	QueryPerformanceCounter(&timer.begin);
	m_timers[handler] = timer;
}

void HighPerformanceTimerThread::DeleteTimer(UINT handler)
{
	std::map<UINT,Timer>::iterator iter = m_timers.find(handler);
	if (iter != m_timers.end())
	{
		delete iter->second.callback;
		m_timers.erase(iter);
	}
}

void HighPerformanceTimerThread::Run()
{
	LARGE_INTEGER freqtime;
	SetThreadAffinityMask(GetCurrentThread(),0x0e);
	QueryPerformanceFrequency(&freqtime);

	bool quitFlag = false;
	while (!quitFlag)
	{
		TriggerTimer(freqtime);
		OnCommand(quitFlag);
	}
}

void HighPerformanceTimerThread::OnCommand(bool& quitFlag)
{
	while (m_queue.Size() > 0)
	{
		ProcessCommand(quitFlag);
	}
	while (IsEmpty() && !quitFlag)
	{
		ProcessCommand(quitFlag);
	}
}

void HighPerformanceTimerThread::ProcessCommand(bool& quitFlag)
{
	QueueItem const& item = m_queue.Pop(quitFlag);
	if (item.type == QueueItem::TIMER_COMMAND)
	{
		TimerCommand const& cmd = *(TimerCommand*)item.data;
		switch (cmd.type)
		{
		case TimerCommand::ADD_TIMER_COMMAND:
			{
				AddTimer(cmd.handler,cmd.period,cmd.callback);
			}
			break;
		case TimerCommand::DELETE_TIMER_COMMAND:
			{
				DeleteTimer(cmd.handler);
			}
			break;
		default:
			break;
		}
	}
}

void HighPerformanceTimerThread::TriggerTimer(LARGE_INTEGER const& freqtime)
{
	if (m_timers.empty())
	{
		return;
	}
	for (std::map<UINT,Timer>::iterator iter = m_timers.begin();
		iter != m_timers.end();
		++iter)
	{
		LARGE_INTEGER endtime = {0};
		QueryPerformanceCounter(&endtime);
		_int64 ms = (endtime.QuadPart - iter->second.begin.QuadPart) *1000 / freqtime.QuadPart;
		_int64 c = ms / iter->second.period;
		if (c > iter->second.counter)
		{
			iter->second.counter = c;
			iter->second.callback->Callback();
		}
	}
}